package com.hqd.ch03.v50.context.event;

import com.hqd.ch03.v50.context.ApplicationEvent;
import com.hqd.ch03.v50.context.ApplicationListener;
import com.hqd.ch03.v50.core.ResolvableType;

import java.util.function.Predicate;

public interface ApplicationEventMulticaster {

    /**
     * Add a listener to be notified of all events.
     *
     * @param listener the listener to add
     * @see #removeApplicationListener(ApplicationListener)
     * @see #removeApplicationListeners(Predicate)
     */
    void addApplicationListener(ApplicationListener<?> listener);

    /**
     * Add a listener bean to be notified of all events.
     *
     * @param listenerBeanName the name of the listener bean to add
     * @see #removeApplicationListenerBean(String)
     * @see #removeApplicationListenerBeans(Predicate)
     */
    void addApplicationListenerBean(String listenerBeanName);

    /**
     * Remove a listener from the notification list.
     *
     * @param listener the listener to remove
     * @see #addApplicationListener(ApplicationListener)
     * @see #removeApplicationListeners(Predicate)
     */
    void removeApplicationListener(ApplicationListener<?> listener);

    /**
     * Remove a listener bean from the notification list.
     *
     * @param listenerBeanName the name of the listener bean to remove
     * @see #addApplicationListenerBean(String)
     * @see #removeApplicationListenerBeans(Predicate)
     */
    void removeApplicationListenerBean(String listenerBeanName);

    /**
     * Remove all matching listeners from the set of registered
     * {@code ApplicationListener} instances (which includes adapter classes
     * such as {@link ApplicationListenerMethodAdapter}, e.g. for annotated
     * {@link EventListener} methods).
     * <p>Note: This just applies to instance registrations, not to listeners
     * registered by bean name.
     *
     * @param predicate the predicate to identify listener instances to remove,
     *                  e.g. checking {@link SmartApplicationListener#getListenerId()}
     * @see #addApplicationListener(ApplicationListener)
     * @see #removeApplicationListener(ApplicationListener)
     * @since 5.3.5
     */
    void removeApplicationListeners(Predicate<ApplicationListener<?>> predicate);

    /**
     * Remove all matching listener beans from the set of registered
     * listener bean names (referring to bean classes which in turn
     * implement the {@link ApplicationListener} interface directly).
     * <p>Note: This just applies to bean name registrations, not to
     * programmatically registered {@code ApplicationListener} instances.
     *
     * @param predicate the predicate to identify listener bean names to remove
     * @see #addApplicationListenerBean(String)
     * @see #removeApplicationListenerBean(String)
     * @since 5.3.5
     */
    void removeApplicationListenerBeans(Predicate<String> predicate);

    /**
     * Remove all listeners registered with this multicaster.
     * <p>After a remove call, the multicaster will perform no action
     * on event notification until new listeners are registered.
     *
     * @see #removeApplicationListeners(Predicate)
     */
    void removeAllListeners();

    /**
     * Multicast the given application event to appropriate listeners.
     * <p>Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)}
     * if possible as it provides better support for generics-based events.
     *
     * @param event the event to multicast
     */
    void multicastEvent(ApplicationEvent event);

    /**
     * Multicast the given application event to appropriate listeners.
     * <p>If the {@code eventType} is {@code null}, a default type is built
     * based on the {@code event} instance.
     *
     * @param event     the event to multicast
     * @param eventType the type of event (can be {@code null})
     * @since 4.2
     */
    void multicastEvent(ApplicationEvent event, ResolvableType eventType);

}
